package com.xiaoshuidi.cloud.module.iot.dal.repository;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xiaoshuidi.cloud.framework.tenant.core.aop.TenantIgnore;
import com.xiaoshuidi.cloud.module.iot.dal.mapper.DeviceDosageDoMapper;
import com.xiaoshuidi.cloud.module.iot.dal.model.watermeter.details.WaterMeterReportListModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.watermeter.details.WaterMeterReportRequestModel;
import com.xiaoshuidi.cloud.module.iot.dal.pojo.TbDeviceDosageDo;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Repository;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author Feng
 * @date 2023/6/17
 */
@Repository
public class DeviceDosageRepository extends ServiceImpl<DeviceDosageDoMapper, TbDeviceDosageDo> {

    /**
     * 根据设备编号和时间查询tb_device_dosage列表
     *
     * @param waterMeterReportRequestModel
     * @return
     */
    public PageInfo<WaterMeterReportListModel> getDeviceDosageByDeviceNoAndTime(WaterMeterReportRequestModel waterMeterReportRequestModel) {
        PageHelper.startPage(waterMeterReportRequestModel.getPageNum(), waterMeterReportRequestModel.getPageSize());
        String queryBeginTime = null;
        String queryEndTime = null;
        if (waterMeterReportRequestModel.getQueryBeginTime() != null && waterMeterReportRequestModel.getQueryBeginTime() != 0) {
            queryBeginTime = DateUtil.format(new Date(waterMeterReportRequestModel.getQueryBeginTime()), "yyyy-MM-dd HH:mm:ss");
        }
        if (waterMeterReportRequestModel.getQueryEndTime() != null && waterMeterReportRequestModel.getQueryEndTime() != 0) {
            queryEndTime = DateUtil.format(new Date(waterMeterReportRequestModel.getQueryEndTime()), "yyyy-MM-dd HH:mm:ss");
        }

        QueryWrapper<WaterMeterReportRequestModel> wrapper = Wrappers.query();
        wrapper.eq("t.device_no", waterMeterReportRequestModel.getDeviceNo())
                .eq("t.`status`", 1)
                .ge(StrUtil.isNotEmpty(queryBeginTime), "t.create_time", queryBeginTime)
                .le(StrUtil.isNotEmpty(queryEndTime), "t.create_time", queryEndTime)
                .orderByDesc("t.dosage_date");

        List<WaterMeterReportListModel> watermeterReportListVOList = this.baseMapper.getDeviceDosageByDeviceNoAndTime(wrapper);
        return new PageInfo<WaterMeterReportListModel>(watermeterReportListVOList);
    }


    /**
     * 根据设备编号和时间查询tb_device_dosage列表(无分页)
     *
     * @param waterMeterReportRequestModel
     * @return
     */
    public List<TbDeviceDosageDo> getDeviceDosageByDeviceNoAndTimeNoPage(WaterMeterReportRequestModel waterMeterReportRequestModel) {
        String queryBeginTime = null;
        String queryEndTime = null;
        if (waterMeterReportRequestModel.getQueryBeginTime() != null && waterMeterReportRequestModel.getQueryBeginTime() != 0) {
            queryBeginTime = DateUtil.format(new Date(waterMeterReportRequestModel.getQueryBeginTime()), "yyyy-MM-dd");
        }
        if (waterMeterReportRequestModel.getQueryEndTime() != null && waterMeterReportRequestModel.getQueryEndTime() != 0) {
            queryEndTime = DateUtil.format(new Date(waterMeterReportRequestModel.getQueryEndTime()), "yyyy-MM-dd");
        }
//        QueryWrapper<WaterMeterReportRequestModel> wrapper = Wrappers.query();
//        wrapper.eq("t.device_no", waterMeterReportRequestModel.getDeviceNo())
//                .eq("t.status", 1)
//                .eq("t.deleted",0)
//                .ge(StrUtil.isNotEmpty(queryBeginTime), "t.dosage_date", queryBeginTime)
//                .le(StrUtil.isNotEmpty(queryEndTime), "t.dosage_date", queryEndTime)
//                .groupBy("t.dosage_date")
//                .orderByDesc("t.dosage_date");
//        List<TbDeviceDosageDo> watermeterReportListVOList = this.baseMapper.getDeviceDosage(wrapper);

        //  需要把峰谷电查询出来，并且还要兼容水表和旧数据
        LambdaQueryWrapper<TbDeviceDosageDo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(TbDeviceDosageDo::getDeviceNo, waterMeterReportRequestModel.getDeviceNo());
        lambdaQueryWrapper.eq(TbDeviceDosageDo::getStatus, 1);
        lambdaQueryWrapper.eq(TbDeviceDosageDo::getDeleted, 0);
        lambdaQueryWrapper.ge(StrUtil.isNotEmpty(queryBeginTime), TbDeviceDosageDo::getDosageDate, queryBeginTime);
        lambdaQueryWrapper.le(StrUtil.isNotEmpty(queryEndTime), TbDeviceDosageDo::getDosageDate, queryEndTime);
        List<TbDeviceDosageDo> list = this.baseMapper.selectList(lambdaQueryWrapper);
        List<TbDeviceDosageDo> watermeterReportListVOList = new ArrayList<>();
        if (CollectionUtils.isEmpty(list)) {
            return watermeterReportListVOList;
        }
        Map<LocalDate, List<TbDeviceDosageDo>> collect = list.stream().collect(Collectors.groupingBy(TbDeviceDosageDo::getDosageDate));
        collect.forEach((k, v) -> {
            TbDeviceDosageDo tbDeviceDosageDo = new TbDeviceDosageDo();
            tbDeviceDosageDo.setDosageDate(k);
            // 水表读数存在常规读数里，水表没有峰谷读数的，并且旧数据也能兼容
            Double minNormalReading = v.stream().map(TbDeviceDosageDo::getStartAmount).filter(Objects::nonNull).min(Double::compareTo).orElse(0d);
            Double minSpikeReading = v.stream().map(TbDeviceDosageDo::getSpikeStartReading).filter(Objects::nonNull).min(Double::compareTo).orElse(0d);
            Double minPeakReading = v.stream().map(TbDeviceDosageDo::getPeakStartReading).filter(Objects::nonNull).min(Double::compareTo).orElse(0d);
            Double minPlainReading = v.stream().map(TbDeviceDosageDo::getPlainStartReading).filter(Objects::nonNull).min(Double::compareTo).orElse(0d);
            Double minValleyReading = v.stream().map(TbDeviceDosageDo::getValleyStartReading).filter(Objects::nonNull).min(Double::compareTo).orElse(0d);
            tbDeviceDosageDo.setStartAmount(minNormalReading);
            tbDeviceDosageDo.setSpikeStartReading(minSpikeReading);
            tbDeviceDosageDo.setPeakStartReading(minPeakReading);
            tbDeviceDosageDo.setPlainStartReading(minPlainReading);
            tbDeviceDosageDo.setValleyStartReading(minValleyReading);

            Double maxNormalReading = v.stream().map(TbDeviceDosageDo::getEndAmount).filter(Objects::nonNull).max(Double::compareTo).orElse(0d);
            Double maxSpikeReading = v.stream().map(TbDeviceDosageDo::getSpikeEndReading).filter(Objects::nonNull).max(Double::compareTo).orElse(0d);
            Double maxPeakReading = v.stream().map(TbDeviceDosageDo::getPeakEndReading).filter(Objects::nonNull).max(Double::compareTo).orElse(0d);
            Double maxPlainReading = v.stream().map(TbDeviceDosageDo::getPlainEndReading).filter(Objects::nonNull).max(Double::compareTo).orElse(0d);
            Double maxValleyReading = v.stream().map(TbDeviceDosageDo::getValleyEndReading).filter(Objects::nonNull).max(Double::compareTo).orElse(0d);
            tbDeviceDosageDo.setEndAmount(maxNormalReading);
            tbDeviceDosageDo.setSpikeEndReading(maxSpikeReading);
            tbDeviceDosageDo.setPeakEndReading(maxPeakReading);
            tbDeviceDosageDo.setPlainEndReading(maxPlainReading);
            tbDeviceDosageDo.setValleyEndReading(maxValleyReading);

            // 实际数据库存的只是常规用电的总用量，不含尖峰平谷的
            tbDeviceDosageDo.setTotalAmount(maxNormalReading - minNormalReading);

            Double normalAmount = v.stream().map(TbDeviceDosageDo::getAmount).filter(Objects::nonNull).max(Double::compareTo).orElse(0d);
            Double spikeAmount = v.stream().map(TbDeviceDosageDo::getSpikeAmount).filter(Objects::nonNull).max(Double::compareTo).orElse(0d);
            Double peakAmount = v.stream().map(TbDeviceDosageDo::getPeakAmount).filter(Objects::nonNull).max(Double::compareTo).orElse(0d);
            Double plainAmount = v.stream().map(TbDeviceDosageDo::getPlainAmount).filter(Objects::nonNull).max(Double::compareTo).orElse(0d);
            Double valleyAmount = v.stream().map(TbDeviceDosageDo::getValleyAmount).filter(Objects::nonNull).max(Double::compareTo).orElse(0d);

            // 实际数据库存的只是常规用电的金额，不含尖峰平谷的
            tbDeviceDosageDo.setAmount(normalAmount);
            tbDeviceDosageDo.setSpikeAmount(spikeAmount);
            tbDeviceDosageDo.setPeakAmount(peakAmount);
            tbDeviceDosageDo.setPlainAmount(plainAmount);
            tbDeviceDosageDo.setValleyAmount(valleyAmount);

            watermeterReportListVOList.add(tbDeviceDosageDo);
        });
        watermeterReportListVOList.sort(Comparator.comparing(TbDeviceDosageDo::getDosageDate).reversed());
        return watermeterReportListVOList;
    }


    /**
     * 根据dosage_data查询当天设备读数上传记录
     *
     * @param deviceNo
     * @param dosageDate
     * @return
     */
    public List<TbDeviceDosageDo> getDeviceDosageListByDate(String deviceNo, Date dosageDate) {
        LambdaQueryWrapper<TbDeviceDosageDo> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(TbDeviceDosageDo::getStatus, 1)
                .eq(TbDeviceDosageDo::getDeviceNo, deviceNo)
                .eq(TbDeviceDosageDo::getDosageDate, dosageDate);
        return list(wrapper);
    }


    @TenantIgnore
    public long countDeviceDosageByDeviceNo(String deviceNo) {
        LambdaQueryWrapper<TbDeviceDosageDo> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(TbDeviceDosageDo::getDeviceNo, deviceNo).eq(TbDeviceDosageDo::getStatus, 1);
        return count(wrapper);

    }
    @TenantIgnore
    public TbDeviceDosageDo getTbDeviceDosageDo(String deviceNo) {
        LambdaQueryWrapper<TbDeviceDosageDo> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(TbDeviceDosageDo::getStatus, 1)
                .eq(TbDeviceDosageDo::getDeviceNo, deviceNo)
                .orderByDesc(TbDeviceDosageDo::getDosageDate)
                .last("limit 1");
    return getOne(wrapper);
    }
    @TenantIgnore
    public Double getOneDayRead(String deviceNo) {
        return this.baseMapper.getOneDayRead(deviceNo);
    }

    public int removeRoomDevice(String deviceNo){
        QueryWrapper<TbDeviceDosageDo> wrapper = new QueryWrapper();
        wrapper.eq("device_no",deviceNo);
        return this.baseMapper.delete(wrapper);
    }
}
